/**
 @date 2022-09-08

 @version v1.0
---file comments----
*/

/****************************************************************************
 *
 * Header files
 *
 *****************************************************************************/
#include "sal.h"
#include "asw/include/drv_api.h"
#include "asw/include/drv_io.h"

#include "ctc_cli.h"
#include "ctc_cli_common.h"
#include "ctcs_api.h"
#include "ctc_qos_cli.h"
#include "api/include/ctcs_api.h"
#include "ctc_common.h"
#include "ctc_diag_cli.h"


extern int32
_drv_asw_chip_sram_tbl_read(uint8 lchip, uint32 tbl_id, uint32 index, uint32* data);
extern int32
_drv_asw_chip_sram_tbl_write(uint8 lchip, uint32 tbl_id, uint32 index, uint32* data);
extern int32
drv_asw_chip_write(uint8 lchip, addrs_t offset, uint32* p_value, uint32 len);
extern int32
drv_asw_chip_read(uint8 lchip, addrs_t offset, uint32* p_value, uint32 len);

int32
ctc_cli_asw_qos_get_monitor_glb_pool_state(ctc_vti_t* vty, uint8 lchip)
{
    uint32 cmd = 0;
    uint32 value = 0;
    ds_t ds;
    int32 ret = CTC_E_NONE;
    cmd = DRV_IOR(IngMmuGlbCnt_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &ds);
    
    ctc_cli_out("Ingress mmu glb cnt\n");
    ctc_cli_out("------------------------------------\n");
    value = GetIngMmuGlbCnt(V,pktCnt_f, &ds);
    ctc_cli_out("%-30s: %d\n", "--Packet in used counter", value);
    value = GetIngMmuGlbCnt(V,cellCnt_f, &ds);
    ctc_cli_out("%-30s: %d\n", "--Cell pointer in used counter", value);
    ctc_cli_out("------------------------------------\n");

    cmd = DRV_IOR(MmuCellPoolDebug_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &ds);

    ctc_cli_out("\nMmu cell pool debug\n");
    ctc_cli_out("------------------------------------\n");
    value = GetMmuCellPoolDebug(V, poolFull_f, &ds);
    if (value)
    {
        ctc_cli_out("%-30s: %d\n", "--Pool full", value);
    }
    value = GetMmuCellPoolDebug(V, poolEmpty_f, &ds);
    if (value)
    {
        ctc_cli_out("%-30s: %d\n", "--Pool empty", value);
    }
    value = GetMmuCellPoolDebug(V, poolTailErr_f, &ds);
    if (value)
    {
        ctc_cli_out("%-30s: %d\n", "--pool tail err", value);
    }
    value = GetMmuCellPoolDebug(V, poolFullErr_f, &ds);
    if (value)
    {
        ctc_cli_out("%-30s: %d\n", "--pool full err", value);
    }
    value = GetMmuCellPoolDebug(V, poolDeep_f, &ds);
    ctc_cli_out("%-30s: %d\n", "--Pool deep", value);
    value = GetMmuCellPoolDebug(V, poolEmptyDrop_f, &ds);
    if (value)
    {
        ctc_cli_out("%-30s: %d\n", "--Pool empty drop", value);
    }
    value = GetMmuCellPoolDebug(V, recycleFifoFullErr_f, &ds);
    if (value)
    {
        ctc_cli_out("%-30s: %d\n", "--Recycle fifo full err", value);
    }
    value = GetMmuCellPoolDebug(V, assignFifoDeep_f, &ds);
    ctc_cli_out("%-30s: %d\n", "--Assign fifo deep", value);
    ctc_cli_out("------------------------------------\n");

    return ret;

}

int32 
ctc_cli_asw_qos_get_monitor_port_state(ctc_vti_t* vty, uint8 lchip, uint32 gport)
{
    uint32 cmd = 0;
    ds_t ds;
    int32 ret = CTC_E_NONE;
    uint8 value = 0;
    if (gport > (MAX_PORT_NUM-1))
    {
        ret =  CTC_E_INVALID_PARAM;
    }

    cmd = DRV_IOR(IngMmuPortState_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, gport, cmd, &ds);
    value = GetIngMmuPortState(V, pktState_f, &ds);
    
    ctc_cli_out("Incoming port packet buffer status:\n");
    switch (value)
    {
        case 0:
            ctc_cli_out("--Minimum guaranteed status\n");
            break;
        case 0x1:
            ctc_cli_out("--Share status\n");
            break;
        case 0x2:
            ctc_cli_out("--Pause status\n");
            break;
        case 0x3:
            ctc_cli_out("--Drop status\n");
            break;
        default:
            ctc_cli_out("--Minimum guaranteed status\n");
            break;
    }
    value = GetIngMmuPortState(V, cellState_f, &ds);
    ctc_cli_out("\nIncoming port cell buffer status:\n");
    switch (value)
    {
        case 0:
            ctc_cli_out("--Minimum guaranteed status\n");
            break;
        case 0x1:
            ctc_cli_out("--Share status\n");
            break;
        case 0x2:
            ctc_cli_out("--Pause status\n");
            break;
        case 0x3:
            ctc_cli_out("--Drop status\n");
            break;
        default:
            ctc_cli_out("--Minimum guaranteed status\n");
            break;
    }

    return ret;
}

extern uint8 g_acl_key_size[CTC_ACL_KEY_NUM];
extern uint8 g_acl_hw_key_type[];

int32
ctc_cli_asw_acl_get_entry_all(ctc_vti_t* vty, uint8 lchip, acl_entry_para_t* p_acl_entry_para, uint32* total_num)
{
    uint32 cmd = 0;
    uint8 key_type = 0;
    uint8 tmp_key_type = 0;
    uint16 index_tmp = 0;
    uint16 loop_entry_id = 0;
    ds_t tmp_key = {0};
    ds_t tmp_mask = {0};
    mask_tbl_entry_t tcam_entry;
    ds_t action = {0};
    uint8 tmp_action = 0;
    uint32 num = 0;
    uint32 size = 0;
    
    tcam_entry.data_entry = tmp_key;
    tcam_entry.mask_entry = tmp_mask;
    do{
        cmd = DRV_IOR(Key160MacView0_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_MASK_IOCTL(lchip, loop_entry_id, cmd, &tcam_entry));
    
        if (GetKey160MacView0(V, valid_f, tmp_key) == 0)
        {
            loop_entry_id ++;
            continue;
        }

        tmp_key_type = GetKey160MacView0(V, keyType_f, tmp_key);
        key_type = g_acl_hw_key_type[tmp_key_type];
    
        switch (loop_entry_id % 4)
        {
        case 0:
        case 2:
            index_tmp = loop_entry_id;
            break;
        case 1:
            if (g_acl_key_size[key_type] == 2)
            {
                index_tmp = loop_entry_id - 1;
            }
            else
            {
                index_tmp = loop_entry_id;
            }
            break;
        case 3:
            if (g_acl_key_size[key_type] == 4)
            {
                index_tmp = loop_entry_id - 3;
            }
            else if (g_acl_key_size[key_type] == 2)
            {
                index_tmp = loop_entry_id - 1;
            }
            else
            {
                index_tmp = loop_entry_id;
            }
            break;
        default:
            break;
        }

        cmd = DRV_IOR(AclBaseAction_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index_tmp, cmd, &action));
        tmp_action = GetAclBaseAction(V, drop_f, action);
        size = ACL_1X_ENTRY_SIZE * g_acl_key_size[key_type];
        p_acl_entry_para[num].table_index = index_tmp;
        p_acl_entry_para[num].key_type = tmp_key_type;
        p_acl_entry_para[num].action_type = tmp_action;
        p_acl_entry_para[num].size = size;
        loop_entry_id ++;

        num ++;
    }
    while (loop_entry_id < MAX_ACL_ENTRY_REG_NUM);

    *total_num = num;

    return CTC_E_NONE;
}


int32
ctc_cli_asw_vlan_get_mapping_all(ctc_vti_t* vty, uint8 lchip, vlan_mapping_para_t* p_vlan_mapping_para, uint32 *total_num)
{
    uint32 num = 0;
    uint16 index = 0;
    int32 ret = CTC_E_NONE;
    hdump_entry_t   data_dump;
    uint8* p_data = NULL;
    XlateIpv6Key_m* xlate = NULL;
    uint32 cmd = 0;
    PeCpuAccessHashReq_m acc_req;
    PeCpuAccessHashStatus_m acc_status;
    ds_t  ds;
    uint16  loop = 0;
    uint32 timeout = 10000;
    const tables_info_t *ptbl;
    /*cam*/
    mask_tbl_entry_t cam_key;
    IvmXReg_m ivm_x_reg_result;
    IvmXMaskReg_m ivm_x_mask_reg_result;
    cam_key.data_entry = (uint32 *)&ivm_x_reg_result;
    cam_key.mask_entry = (uint32 *)&ivm_x_mask_reg_result;
    
    sal_memset(&data_dump, 0, sizeof(hdump_entry_t));
    xlate = (XlateIpv6Key_m*)mem_malloc(MEM_CLI_MODULE, sizeof(XlateIpv6Key_m)*256);
    
    ptbl = &drv_tbls_list[XlateIpv6Key_t];
    if (NULL == xlate)
    {
        ctc_cli_out("%% Alloc  memory  failed \n");
        return CLI_ERROR;
    }
    
    data_dump.data_entry = (uint32*)xlate;
    p_data = (uint8*)(data_dump.data_entry);
    data_dump.entry_num = MAX_VLAN_HASH_REG_NUM;
    data_dump.start_index = 0;


    while(loop++ < data_dump.entry_num)
    {
        /*1. reset  hash read */
        SetPeCpuAccessHashReq(V,searchStart_f,&acc_req,0);
        SetPeCpuAccessHashReq(V,searchType_f,&acc_req,2);//search next valid from last search address
        SetPeCpuAccessHashReq(V,directAddr_f,&acc_req,data_dump.next_index);
        _drv_asw_chip_sram_tbl_write(lchip,  PeCpuAccessHashReq_t, 0,(uint32*)&acc_req);
    
        /*2. triger  hash read */
        SetPeCpuAccessHashReq(V,searchStart_f,&acc_req,1);
        _drv_asw_chip_sram_tbl_write(lchip,  PeCpuAccessHashReq_t, 0,(uint32*)&acc_req);
    
        /*3. wait status */
        do
        {
            _drv_asw_chip_sram_tbl_read(lchip,  PeCpuAccessHashStatus_t, 0,(uint32*)&acc_status);
        }while(!GetPeCpuAccessHashStatus(V,searchDone_f,&acc_status) && timeout--);
    
        if(!GetPeCpuAccessHashStatus(V,searchDone_f,&acc_status))
        {
            ret = DRV_E_TIME_OUT;
            break;
        }
        if((!GetPeCpuAccessHashStatus(V,hitMiss_f,&acc_status)) || ((data_dump.next_index) > (MAX_VLAN_HASH_REG_NUM-1)))
        {
            data_dump.next_index = 0;
            ret = DRV_E_NONE;
            break;
        }
        
        p_vlan_mapping_para[num].key_type = GetPeCpuAccessHashStatus(V,keyType_f,&acc_status);
        /*4.get table index*/
        _drv_asw_chip_sram_tbl_read(lchip,  PeCpuAccessHashAddr_t, 0,(uint32*)&ds);
        p_vlan_mapping_para[num].table_index = GetPeCpuAccessHashAddr(V,tablePtr_f,&ds);
        data_dump.next_index = p_vlan_mapping_para[num].table_index +1;
        num ++;
        /*5.Get  hash read */
        _drv_asw_chip_sram_tbl_read(lchip,  PeCpuAccessHashRdata_t, 0,(uint32*)p_data);
        p_data += ptbl->entry_size;
        data_dump.valid_num++;
    }


    sal_memset(&ivm_x_reg_result, 0, sizeof(IvmXReg_m));
    sal_memset(&ivm_x_mask_reg_result, 0, sizeof(IvmXMaskReg_m));
    for (index = 0; index < MAX_IVM_X_REG_NUM; index++)
    {
        cmd = DRV_IOR(IvmXReg_t, DRV_ENTRY_FLAG);
        ret = DRV_MASK_IOCTL(lchip, index, cmd, &cam_key);
        if (GetIvmXReg(V, valid_f, &ivm_x_reg_result))
        {
            p_vlan_mapping_para[num].key_type = VLAN_IVM_X_REG_NUM;/*ivm_x_reg*/
            p_vlan_mapping_para[num].table_index = index;
            num ++;
        }
    }
    *total_num = num;

    return ret;
}


#define CTC_ASW_RW_BUF_SIZE             256
#define CTC_ASW_MAX_ENTRY_WORD          60
#define CTC_ASW_INVALID_TBL_ID          0xFFFF
#define CTC_ASW_PRINT(X, ...)  \
    do { \
                ctc_cli_out(X, ##__VA_ARGS__); \
    } while (0)

#define CTC_ASW_MAX_CHIP_NUM 1
#define CTC_ASW_HEX_FORMAT(S, F, V, W)                        \
                            ((sal_sprintf(F, "0x%%0%dX", W))   \
                             ? ((sal_sprintf(S, F, V)) ? S : NULL) : NULL)

enum ctc_asw_memory_rw_type_e
{
    CTC_ASW_MEMORY_LIST = 0,
    CTC_ASW_MEMORY_READ,
    CTC_ASW_MEMORY_WRITE,
    CTC_ASW_MEMORY_CHECK,
    CTC_ASW_MEMORY_MAX
} ;
typedef enum ctc_asw_memory_rw_type_e ctc_asw_memory_rw_type_t;
struct ctc_asw_memory_para_s
{
    ctc_asw_memory_rw_type_t type;
    uintptr  param[8];/*  0      1      2      3        4        5       6   */
                          /*read:  opcode, chip, index, tbl-id,  count    step*/
                          /*write: opcode, chip, index, tbl-id,  fld-id,  value, count */
    uint32 value[CTC_ASW_MAX_ENTRY_WORD];
    uint32 mask[CTC_ASW_MAX_ENTRY_WORD];

    uint8    buf[CTC_ASW_RW_BUF_SIZE];/*table name*/
    uint8    buf2[CTC_ASW_RW_BUF_SIZE];/*field name*/
    uint8    detail;
    uint8    grep;

    uint8    direct_io;
    uint8    rev[3];
};
typedef struct ctc_asw_memory_para_s ctc_asw_memory_para_t;

static ctc_asw_memory_para_t memory_para_com;

#define TABLE_INFO_PTR(lchip, tbl_id)             (&drv_tbls_list[tbl_id])
#define TABLE_INFO(lchip, tbl_id)                 (drv_tbls_list[tbl_id])
#define TABLE_DATA_BASE(lchip, tbl_id)            (TABLE_INFO(lchip, tbl_id).addrs[0])
#define TABLE_ENTRY_SIZE(lchip, tbl_id)           ((TABLE_INFO(lchip, tbl_id).entry_size+3)>>2)
#define TABLE_MAX_ADDR_OFFSET(lchip, tbl_id)      ((TABLE_MAX_INDEX(lchip, tbl_id))*(TABLE_ENTRY_SIZE(lchip, tbl_id)))
#define TABLE_DATA_END_ADDR(lchip, tbl_id)        ((TABLE_DATA_BASE(lchip, tbl_id))+(TABLE_MAX_ADDR_OFFSET(lchip, tbl_id)))
#define TABLE_OP_TYPE(lchip, tbl_id)           (TABLE_INFO(lchip, tbl_id).optype)
#define TABLE_TYPE(lchip, tbl_id)           (TABLE_INFO(lchip, tbl_id).tbl_type)
#define TABLE_NAME(lchip, tbl_id)           (TABLE_INFO(lchip, tbl_id).ptr_tbl_name)

/**
  @driver get table type interface
*/
uint32
drv_asw_get_table_type (uint8 lchip, uint32 tbl_id)
{
    return TABLE_TYPE(lchip, tbl_id);
}

const fields_t *
drv_asw_find_field(uint8 lchip, uint32 tbl_id, uint32 field_id)
{
    const fields_t *p_fld = NULL;

    if (lchip >= CTC_ASW_MAX_CHIP_NUM)
    {
        return NULL;
    }
    if (tbl_id >= MaxTblId_t)
    {
        DRV_DBG_INFO("ERROR! INVALID TblID or fieldID! TblID: %d, fieldID: %d\n", tbl_id, field_id);
        return NULL;
    }

    p_fld = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;


    if (0 == TABLE_FIELD_NUM(lchip, tbl_id) || field_id >= TABLE_FIELD_NUM(lchip, tbl_id) || 0 == p_fld->bits)
    {
        DRV_DBG_INFO("ERROR! (drv_asw_mem_get_field): memID-%d, field-%d is not supported\n", tbl_id, field_id);
        return NULL;
    }

    return p_fld;
}
/**
 @brief
*/
int32
drv_asw_get_tbl_string_by_id(uint8 lchip, uint32 tbl_id, char* name)
{
    if (!name)
    {
        return -1;
    }

    if (tbl_id < MaxTblId_t)
    {
         sal_strcpy(name, TABLE_NAME(lchip, tbl_id));
         return DRV_E_NONE;
    }

    return DRV_E_INVALID_TBL;
}

/**
 @brief
*/
int32
drv_asw_get_field_string_by_id(uint8 lchip, uint32 tbl_id, uint32 field_id, char* name)
{
    const fields_t* ptr_field_info = NULL;

    if (!name)
    {
        return -1;
    }

    ptr_field_info = drv_asw_find_field(lchip, tbl_id, field_id);
    if (NULL != ptr_field_info)
    {
        sal_strcpy(name, ptr_field_info->ptr_fld_name);
    }
    else
    {
        return DRV_E_INVALID_FLD;
    }


    return DRV_E_INVALID_TBL;
}


/**
 @brief
*/
int32
drv_asw_get_tbl_id_by_string(uint8 lchip, uint32* tbl_id, char* name)
{
    uint32 tmp_tableid = 0;

    /* This is so inefficient Code, need to consider to optimize it, add by zhouw??? */
    for (tmp_tableid = 0; tmp_tableid < MaxTblId_t; tmp_tableid++)
    {
        if (0 == TABLE_INFO(lchip, *tbl_id).entry_size)
        {
            continue;
        }
        if (0 == sal_strcasecmp(name, TABLE_NAME(lchip, tmp_tableid)))
        {
            *tbl_id = tmp_tableid;
            return DRV_E_NONE;
        }
    }

    DRV_DBG_INFO("%% Not Find the TableID!! tableName: %s\n", name);

    return DRV_E_INVALID_TBL;
}


int32
drv_asw_get_field_id_by_string(uint8 lchip, uint32 tbl_id, uint32* field_id, char* name)
{
    const fields_t* ptr_field_info = NULL;
    uint32 tmp_index = 0;

    if (tbl_id >= MaxTblId_t)
    {
        DRV_DBG_INFO("ERROR! INVALID TblID or fieldID! TblID: %d\n", tbl_id);
        return DRV_E_INVALID_TBL;
    }

    ptr_field_info = TABLE_FIELD_INFO_PTR(lchip, tbl_id);

    for (tmp_index = 0; tmp_index < TABLE_FIELD_NUM(lchip, tbl_id); tmp_index++)
    {
        if (ptr_field_info[tmp_index].bits == 0)
        {
            continue;
        }
        if (0 == sal_strcasecmp(name, ptr_field_info[tmp_index].ptr_fld_name))
        {
            *field_id = ptr_field_info[tmp_index].field_id;
            return DRV_E_NONE;
        }
    }

    DRV_DBG_INFO("%% Not Find the FieldID!! tableId: %d; Fieldname: %s\n", tbl_id, name);

    return DRV_E_INVALID_FLD;
}

STATIC char*
_ctc_asw_asw_memory_tbl_type_to_str(uint8 type)
{
    switch (type)
    {
        case TBL_SRAM:
            return "SRAM";

        case TBL_SRAM_MASK:
            return "SRAM_MASK";
        case TBL_HASH:
            return "HASH";

        default:
            return "SRAM";
    }
}

STATIC char*
_ctc_asw_asw_memory_tblreg_dump_list_one(ctc_vti_t* vty, uint8 lchip, uint32 tbl_id, uint32* first_flag, uint8 detail)
{
    uint32 addr = 0;
    uint32 entry = 0;
    uint32 word = 0;
    uint32 field_num = 0;

    entry = TABLE_MAX_INDEX(lchip, tbl_id);
    word = TABLE_ENTRY_SIZE(lchip, tbl_id);
    field_num = TABLE_FIELD_NUM(lchip, tbl_id);
    addr = TABLE_DATA_BASE(lchip, tbl_id);
    if (*first_flag)
    {
        if(detail)
        {
            CTC_ASW_PRINT("%-5s %-10s %-6s %-7s %-8s %-15s %-9s %-20s\n", \
                        "TblID", "Address",  "Number", "EntrySZ", "Fields", "Type", "Slice", "TblName");
            CTC_ASW_PRINT("----------------------------------------------------------------------------------\n");

        }
        else
        {

        }
        *first_flag = FALSE;
    }

    if(detail)
    {
        CTC_ASW_PRINT("%-5d 0x%08x %-6d %-7d %-8d %-15s %-9s %-20s\n",
                    tbl_id, addr,  entry,
                    word, field_num, _ctc_asw_asw_memory_tbl_type_to_str(TABLE_TYPE(lchip, tbl_id)),
                    0, TABLE_NAME(lchip, tbl_id));
    }
    else
    {
        CTC_ASW_PRINT(" %s\n",TABLE_NAME(lchip, tbl_id));
    }

    return CLI_SUCCESS;
}

STATIC int32
_ctc_asw_asw_memory_tblreg_dump_chip_read_tbl_db_by_id(ctc_vti_t* vty, uint8 lchip, char* tbl_name, uint32 tbl_id, uint32 detail)
{

    const tables_info_t* tbl_ptr = NULL;
    const fields_t* fld_ptr = NULL;
    uint32 fld_idx = 0;
    uint32 first_flag = TRUE;
    char* ptr_field_name = NULL;

    tbl_ptr = TABLE_INFO_PTR(lchip, tbl_id);
    _ctc_asw_asw_memory_tblreg_dump_list_one(vty, lchip, tbl_id, &first_flag, 1);

    if (detail)
    {
        /* descrption */
        CTC_ASW_PRINT("==================================================================================\n");
        CTC_ASW_PRINT("%-8s %-8s %-8s %-8s %-8s %-30s\n", \
                "FldID","Word", "Bit", "SegLen","TotalLen", "Name");
        CTC_ASW_PRINT("----------------------------------------------------------------------------------\n");

        /* value */
        for (fld_idx = 0; fld_idx < tbl_ptr->field_num; fld_idx++)
        {
            fld_ptr = &(tbl_ptr->ptr_fields[fld_idx]);
            ptr_field_name = fld_ptr->ptr_fld_name;
            if (fld_ptr->bits == 0)
            {
                continue;
            }

            CTC_ASW_PRINT("%-8d %-8d %-8d %-8d %-8d %-30s\n",
                fld_ptr->field_id,
                0, /*fld_ptr->ptr_seg[0].word_offset,*/
                fld_ptr->seg.start,
                fld_ptr->seg.bits,
                fld_ptr->bits,
                ptr_field_name);
            /*for (seg_id = 1; seg_id < fld_ptr->seg_num; seg_id ++)*/
            {
                CTC_ASW_PRINT("%-8s %-8d %-8d %-8d \n",
                " ",
                0, /*fld_ptr->ptr_seg[seg_id].word_offset,*/
                fld_ptr->seg.start,
                fld_ptr->seg.bits);
            }
        }

    }
    CTC_ASW_PRINT("----------------------------------------------------------------------------------\n\n");

    return CLI_SUCCESS;
}


STATIC int32
_ctc_asw_asw_memory_str_to_upper(char* str)
{
    uint32  i = 0;

    /* convert the alphabets to upper case before comparison */
    for (i = 0; i < sal_strlen((char*)str); i++)
    {
        if (sal_isalpha((int)str[i]) && sal_islower((int)str[i]))
        {
            str[i] = sal_toupper(str[i]);
        }
    }

    return CLI_SUCCESS;
}

STATIC int32
_ctc_asw_asw_memory_list_table(ctc_vti_t* vty, uint8 lchip, ctc_asw_memory_para_t* p_memory_para)
{
#define CTC_GOLDENGEAT_LIST_MAX_NUM   9600
    uint32  *ids = NULL;
    char*    upper_name = NULL;
    char*    upper_name1 = NULL;
    char*    upper_name_grep = NULL;
    uint32  i = 0;
    uint32  id_index = 0;
    uint32  first_flag = TRUE;
    char* p_char = NULL;
    int32 ret = CLI_SUCCESS;

    ids = (uint32 *)sal_malloc(CTC_GOLDENGEAT_LIST_MAX_NUM * sizeof(uint32));
    if(ids == NULL)
    {
        CTC_ASW_PRINT("%% No memory\n");
        return CLI_ERROR;
    }
    upper_name = (char*)sal_malloc(CTC_ASW_RW_BUF_SIZE * sizeof(char));
    if(upper_name == NULL)
    {
        CTC_ASW_PRINT("%% No memory\n");
        ret = CLI_ERROR;
        goto clean;
    }
    upper_name1 = (char*)sal_malloc(CTC_ASW_RW_BUF_SIZE * sizeof(char));
    if(upper_name1 == NULL)
    {
        CTC_ASW_PRINT("%% No memory\n");
        ret = CLI_ERROR;
        goto clean;
    }
    upper_name_grep = (char*)sal_malloc(CTC_ASW_RW_BUF_SIZE * sizeof(char));
    if(upper_name_grep == NULL)
    {
        CTC_ASW_PRINT("%% No memory\n");
        ret = CLI_ERROR;
        goto clean;
    }

    sal_memset(ids, 0, CTC_GOLDENGEAT_LIST_MAX_NUM * sizeof(uint32));
    sal_memset(upper_name, 0, CTC_ASW_RW_BUF_SIZE * sizeof(char));
    sal_memset(upper_name1, 0, CTC_ASW_RW_BUF_SIZE * sizeof(char));
    sal_memset(upper_name_grep, 0, CTC_ASW_RW_BUF_SIZE * sizeof(char));

    if (0 == sal_strlen((char*)p_memory_para->buf))
    {
        /* list all */
        CTC_ASW_PRINT("List all %d entries\n", MaxTblId_t);

        for (i = 0; i < MaxTblId_t; i++)
        {
            _ctc_asw_asw_memory_tblreg_dump_list_one(vty, lchip, i, &first_flag, p_memory_para->detail);
        }
        goto clean;
    }

    sal_strncpy((char*)upper_name, (char*)p_memory_para->buf, CTC_ASW_RW_BUF_SIZE-1);
    _ctc_asw_asw_memory_str_to_upper(upper_name);

    if (p_memory_para->grep)
    {
        sal_strncpy((char*)upper_name_grep, (char*)p_memory_para->buf2, CTC_ASW_RW_BUF_SIZE-1);
        _ctc_asw_asw_memory_str_to_upper(upper_name_grep);
    }

    for (i = 0; i < MaxTblId_t; i++)
    {
        drv_asw_get_tbl_string_by_id(lchip, i, (char*)upper_name1);
        _ctc_asw_asw_memory_str_to_upper(upper_name1);

        p_char = (char*)sal_strstr((char*)upper_name1, (char*)upper_name);
        if (p_char)
        {
            if (0 == TABLE_MAX_INDEX(lchip, i))
            {
                continue;
            }

            if (sal_strlen((char*)upper_name1) == sal_strlen((char*)upper_name))
            {
                /* list full matched */
                _ctc_asw_asw_memory_tblreg_dump_chip_read_tbl_db_by_id(vty, lchip, upper_name1, i, p_memory_para->detail);
                goto clean;
            }

            if (p_memory_para->grep)
            {
                p_char = NULL;
                p_char = (char*)sal_strstr((char*)upper_name1, (char*)upper_name_grep);
                if (p_char)
                {
                    ids[id_index] = i;
                    id_index++;
                }
            }
            else
            {
                ids[id_index] = i;
                id_index++;
            }
        }
    }

    if (id_index == 0)
    {
        CTC_ASW_PRINT("%% Not found %s \n", p_memory_para->buf);
        goto clean;
    }

    for (i = 0; i < id_index; i++)
    {
        /* list matched */
        _ctc_asw_asw_memory_tblreg_dump_list_one(vty, lchip, ids[i], &first_flag, p_memory_para->detail);
    }

    if (p_memory_para->detail)
    {
        CTC_ASW_PRINT("----------------------------------------------------------------------------------\n");
    }
    CTC_ASW_PRINT("\n");

clean:
    if(NULL != ids)
    {
        sal_free(ids);
    }
    if(NULL != upper_name)
    {
        sal_free(upper_name);
    }
    if(NULL != upper_name1)
    {
        sal_free(upper_name1);
    }
    if(NULL != upper_name_grep)
    {
        sal_free(upper_name_grep);
    }

    return ret;
}

STATIC int32
_ctc_asw_asw_memory_show_cam_by_data_tbl_id(ctc_vti_t* vty, uint8 lchip, uint32 tbl_id, uint32 index, uint32* data_entry, uint32* mask_entry, char* regex)
{
    uint32* value = NULL;
    uint32* mask = NULL;
    uint8 uint32_id = 0;
    const fields_t* fld_ptr = NULL;
    int32 fld_idx = 0;
    const tables_info_t* tbl_ptr = NULL;
    uint8 print_fld = 0;
    char match_str[100] = {0};

    tbl_ptr = TABLE_INFO_PTR(lchip, tbl_id);

    value = (uint32*)sal_malloc(CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    if(NULL == value)
    {
        return CLI_ERROR;
    }
    mask = (uint32*)sal_malloc(CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    if(NULL == mask)
    {
        sal_free(value);
        return CLI_ERROR;
    }


    for (fld_idx = 0; fld_idx < tbl_ptr->field_num; fld_idx++)
    {
        sal_memset(value, 0 , CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
        sal_memset(mask, 0 , CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
        fld_ptr = &(tbl_ptr->ptr_fields[fld_idx]);
        if (fld_ptr->bits == 0)
        {
            continue;
        }
        drv_asw_get_field(lchip, tbl_id, fld_ptr->field_id, data_entry, value);
        drv_asw_get_field(lchip, tbl_id, fld_ptr->field_id, mask_entry, mask);

        if (NULL == regex)
        {
            if (0 == fld_idx)
            {
                sal_sprintf(match_str, "%-6d %-6d 0x%08x 0x%08x %-6d %-10s", index,  fld_ptr->field_id, value[0], mask[0], fld_ptr->bits, fld_ptr->ptr_fld_name);
            }
            else
            {
                sal_sprintf(match_str, "%-6s %-6d 0x%08x 0x%08x %-6d %-10s", "", fld_ptr->field_id, value[0], mask[0], fld_ptr->bits, fld_ptr->ptr_fld_name);
            }

            print_fld = 1;
        }
        else
        {
            sal_sprintf(match_str, "%-6d %-6d 0x%08x 0x%08x %-6d %-10s", index,  fld_ptr->field_id, value[0], mask[0], fld_ptr->bits, fld_ptr->ptr_fld_name);

            print_fld = ctc_regex_exec(vty, match_str);
        }


        if (print_fld)
        {
            CTC_ASW_PRINT("%s\n", match_str);

            for (uint32_id = 1; uint32_id < ((fld_ptr->bits + 31) / 32); uint32_id ++)
            {
                CTC_ASW_PRINT("%-13s 0x%08x 0x%08x\n", " ", value[uint32_id], mask[uint32_id]);
            }
        }

    }

    if (NULL == regex)
    {
        CTC_ASW_PRINT("----------------------------------------------------------------------------------\n");
    }

    /*CTC_ASW_PRINT_DEBUG("%-6s %-10s  %-10s \n", "Word",  "Addr", "Value");
    for (uint32_id = 0; uint32_id < DRV_TABLE_ENTRY_SIZE(lchip, tbl_id) / DRV_BYTES_PER_WORD; uint32_id ++)
    {
        CTC_ASW_PRINT_DEBUG("%-6d 0x%08x 0x%08x\n", uint32_id, addr + uint32_id*4, *(data_entry + uint32_id));
    }*/

    CTC_ASW_PRINT("\n");

    if(NULL != value)
    {
        sal_free(value);
    }
    if(NULL != mask)
    {
        sal_free(mask);
    }

    return CLI_SUCCESS;

}

int32
_ctc_asw_asw_memory_show_ram_by_data_tbl_id(ctc_vti_t* vty, uint8 lchip,  uint32 tbl_id, uint32 index, uint32* data_entry, char* regex, uint8 acc_io)
{
    uint32 value[CTC_ASW_MAX_ENTRY_WORD] = {0};
    uint8 uint32_id = 0;
    const fields_t* fld_ptr = NULL;
    int32 fld_idx = 0;
    int32 cur_fld_idx = 0;
    char str[35] = {0};
    char format[10] = {0};
    const tables_info_t* tbl_ptr = NULL;
    uint32 field_num = 0;
    char* ptr_field_name = NULL;
    uint8 print_fld = 0;
    char match_str[100] = {0};
    uint32* p_temp_data = NULL;


    p_temp_data = data_entry;


    tbl_ptr = TABLE_INFO_PTR(lchip, tbl_id);
    field_num = tbl_ptr->field_num;


    for (fld_idx = 0; fld_idx < field_num; fld_idx++)
    {
        sal_memset(value, 0 , sizeof(value));
        fld_ptr = &(tbl_ptr->ptr_fields[fld_idx]);
        if (fld_ptr->bits == 0)
        {
            continue;
        }

        drv_asw_get_field(lchip, tbl_id, fld_ptr->field_id, p_temp_data, value);

        cur_fld_idx = fld_ptr->field_id;
        ptr_field_name = fld_ptr->ptr_fld_name;

        if (NULL == regex)
        {
            if (0 == fld_idx)
            {
                sal_sprintf(match_str, "%-8u%-8u%-13s%-9u%-40s", index, cur_fld_idx, CTC_ASW_HEX_FORMAT(str, format, value[0], 8), fld_ptr->bits, ptr_field_name);
            }
            else
            {
                sal_sprintf(match_str, "%-8s%-8u%-13s%-9u%-40s", "", cur_fld_idx, CTC_ASW_HEX_FORMAT(str, format, value[0], 8), fld_ptr->bits, ptr_field_name);
            }

            print_fld = 1;
        }
        else
        {
            sal_sprintf(match_str, "%-8u%-8u%-13s%-9u%-40s", index, cur_fld_idx, CTC_ASW_HEX_FORMAT(str, format, value[0], 8), fld_ptr->bits, ptr_field_name);
            print_fld = ctc_regex_exec(vty, match_str);
        }

        if (print_fld)
        {
            CTC_ASW_PRINT("%s\n", match_str);

            for (uint32_id = 1; uint32_id < ((fld_ptr->bits + 31) / 32); uint32_id++)
            {
                CTC_ASW_PRINT("%-16s%s\n", " ", CTC_ASW_HEX_FORMAT(str, format, value[uint32_id], 8));
            }
        }

    }

    if (NULL == regex)
    {
        CTC_ASW_PRINT("-------------------------------------------------------------\n");
    }
#if 0

    /*Detail addr/data information*/
    if ((DRV_TABLE_TYPE_TCAM != drv_asw_get_table_type(lchip, tbl_id))
        && (DRV_TABLE_TYPE_LPM_TCAM_IP != drv_asw_get_table_type(lchip, tbl_id))
        && (DRV_TABLE_TYPE_LPM_TCAM_NAT != drv_asw_get_table_type(lchip, tbl_id))
        && (DRV_TABLE_TYPE_STATIC_TCAM_KEY != drv_asw_get_table_type(lchip, tbl_id))
        && (PacketHeaderOuter_t != tbl_id))
    {
        uint32 hash_key_type = 0;

        if ((_ctc_asw_asw_memory_is_hash_key(lchip, tbl_id, &hash_key_type)) && acc_io)
        {
            uint8 step = 0;
            uint8 cam_num = 0;
            uint8 hash_module = 0;
            uint32 cam_tbl_id = 0;

            drv_asw_acc_get_hash_module_from_tblid(lchip, tbl_id, &hash_module);
            drv_asw_get_cam_info(lchip, hash_module, &cam_tbl_id, &cam_num);
            if (index < cam_num)
            {
                step =  DRV_TABLE_ENTRY_SIZE(lchip, cam_tbl_id)/DRV_TABLE_ENTRY_SIZE(lchip, tbl_id);
                ret = drv_get_table_property(lchip, DRV_TABLE_PROP_HW_ADDR, cam_tbl_id, (index/step), (uint32*)&addr);
                addr += (index%step)*DRV_TABLE_ENTRY_SIZE(lchip, tbl_id);
            }
            else
            {
                ret = drv_get_table_property(lchip, DRV_TABLE_PROP_HW_ADDR, tbl_id, (index - cam_num), (uint32*)&addr);
            }

        }
        else if (DsFwd_t == tbl_id || DsFwdHalf_t == tbl_id || DsIpfixSessionRecord_t == tbl_id)
        {
            ret = drv_get_table_property(lchip, DRV_TABLE_PROP_HW_ADDR, tbl_id, index/2, (uint32*)&addr);
        }
        else
        {
            ret = drv_get_table_property(lchip, DRV_TABLE_PROP_HW_ADDR, tbl_id, index, (uint32*)&addr);
        }

        if (ret)
        {
            return CLI_ERROR;
        }
    }
    CTC_ASW_PRINT_DEBUG("%-6s %-10s  %-10s \n", "Word",  "Addr", "Value");
    for (uint32_id = 0; uint32_id < DRV_TABLE_ENTRY_SIZE(lchip, tbl_id) / DRV_BYTES_PER_WORD; uint32_id ++)
    {
        CTC_ASW_PRINT_DEBUG("%-6u ", uint32_id);
        CTC_ASW_PRINT_DEBUG("%-10s  ",   CTC_ASW_HEX_FORMAT(str, format, addr + uint32_id * 4, 8));
        CTC_ASW_PRINT_DEBUG("%-10s\n", CTC_ASW_HEX_FORMAT(str, format, *(p_temp_data + uint32_id), 8));
    }
#endif
    return CLI_SUCCESS;
}


int32
_ctc_asw_asw_memory_read_table(ctc_vti_t* vty, uint8 lchip, ctc_asw_memory_para_t* p_memory_para)
{
    char* tbl_name = NULL;
    int32 start_index = 0;
    uint32 count = 0;
    uint8 step = 0;
    uint32 tbl_id = 0;
    int32 ret = CLI_SUCCESS;
    uint32 cmd = 0;
    mask_tbl_entry_t entry;
    uint32* data_entry = NULL;
    uint32* mask_entry = NULL;
    int32 i = 0;
    uint32 index = 0;
    uint32 index_temp = 0;
    char* regex = NULL;

    data_entry = (uint32*)sal_malloc(CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    if(NULL == data_entry)
    {
        return CLI_ERROR;
    }

    mask_entry = (uint32*)sal_malloc(CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    if(NULL == mask_entry)
    {
        sal_free(data_entry);
        return CLI_ERROR;
    }

    sal_memset(data_entry, 0, CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    sal_memset(mask_entry, 0, CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));

    lchip = p_memory_para->param[1];
    start_index = p_memory_para->param[2];
    count = p_memory_para->param[4];
    step = p_memory_para->param[5];
    tbl_name = (char*)p_memory_para->buf;



    if (p_memory_para->grep)
    {
        regex = (char*)p_memory_para->buf2;
    }

    if (NULL != regex)
    {
        char* p = NULL;

        p = ctc_regex_complete(vty, regex);

        if (NULL != p)
        {
            CTC_ASW_PRINT("Not match regex  %s: %s\n", p, regex);
            ret = 0;
            goto clean;
        }
    }



    if (CTC_ASW_INVALID_TBL_ID != p_memory_para->param[3])
    {
        tbl_id = p_memory_para->param[3];
        if((tbl_id) <= 0 || (tbl_id) >= MaxTblId_t)
        {
            ret = CLI_ERROR;
            goto clean;
        }
        drv_asw_get_tbl_string_by_id(lchip, tbl_id, (char*)tbl_name);
    }
    else
    {
        if (drv_asw_get_tbl_id_by_string(lchip, &tbl_id, tbl_name)
            || (0 == TABLE_MAX_INDEX(lchip, tbl_id)))
        {
            CTC_ASW_PRINT("%% Not found %s\n", tbl_name);
            ret = CLI_ERROR;
            goto clean;
        }
    }

    if (TBL_SRAM_MASK == drv_asw_get_table_type(lchip, tbl_id))
    {
        /* CAM */
        CTC_ASW_PRINT("\n%-6s %-6s %-10s %-10s %-6s %-10s\n", "Index", "FldID", "Value", "Mask", "BitLen", "Name");
        CTC_ASW_PRINT("----------------------------------------------------------------------------------\n");

    }
    else
    {
        /* non-CAM */
        CTC_ASW_PRINT("\n%-8s%-8s%-13s%-9s%-40s\n", "Index", "FldID", "Value", "BitLen", "FldName");
        CTC_ASW_PRINT("-------------------------------------------------------------\n");
    }


    for (i = 0; i < count; i++)
    {
        index = (start_index + (i * step));
        if (TBL_SRAM_MASK == drv_asw_get_table_type(lchip, tbl_id))
        {
            entry.data_entry = data_entry;
            entry.mask_entry = mask_entry;
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
            DRV_MASK_IOCTL(lchip, index, cmd, &entry);

            _ctc_asw_asw_memory_show_cam_by_data_tbl_id(vty, lchip, tbl_id, index, data_entry, mask_entry, regex);
        }
        else
        {
#if 0
            if (TBL_HASH = drv_asw_get_table_type(lchip, tbl_id))
            {
                ret =  _ctc_asw_asw_memory_acc_read(lchip, tbl_id, index, hash_key_type, (void*)(data_entry));/*merge table and cam*/
            }
            else
#endif
            {
                uint32 tbl_id_tmp = tbl_id;


                index_temp = index;

                cmd = DRV_IOR(tbl_id_tmp, DRV_ENTRY_FLAG);
                ret = DRV_IOCTL(lchip, index_temp, cmd, data_entry);
            }
            if (CLI_SUCCESS == ret)
            {
                _ctc_asw_asw_memory_show_ram_by_data_tbl_id(vty, lchip, tbl_id, index, data_entry, regex, !p_memory_para->direct_io);
            }
        }
    }
    if (ret < 0)
    {
        CTC_ASW_PRINT("%% Read index %d failed %d\n", index, ret);
    }
clean:
    sal_free(data_entry);
    sal_free(mask_entry);

    return ret;
}

STATIC int32
_ctc_asw_asw_memory_write_table(ctc_vti_t* vty, uint8 lchip, ctc_asw_memory_para_t* p_memory_para)
{
    char* reg_name = NULL;
    char* fld_name = NULL;
    int32 index = 0;
    uint32 index_temp = 0;
    uint32 reg_tbl_id = 0;
    uint32 tmp_reg_tbl_id = 0;
    uint32* p_value = NULL;
    uint32* p_mask = NULL;
    uint32* mask = NULL;
    uint32* value = NULL;
    uint32 cmd = 0;
    int32 ret = 0;
    uint32 fld_id = 0;
    mask_tbl_entry_t field_entry;
    char* fld_name_temp = NULL;

    mask = (uint32*)sal_malloc(CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    value = (uint32*)sal_malloc(CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    fld_name_temp = (char*)sal_malloc(CTC_ASW_MAX_ENTRY_WORD * sizeof(char));

    if (!mask || !value || !fld_name_temp)
    {
        ret = CLI_ERROR;
        goto WRITE_TABLE_ERROR;
    }

    sal_memset(mask, 0, CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    sal_memset(value, 0, CTC_ASW_MAX_ENTRY_WORD * sizeof(uint32));
    sal_memset(fld_name_temp, 0, CTC_ASW_MAX_ENTRY_WORD * sizeof(char));

    lchip = p_memory_para->param[1];
    index_temp = p_memory_para->param[2];
    p_value =(uint32*)p_memory_para->value;
    p_mask = (uint32*)p_memory_para->mask;
    reg_name = (char*)p_memory_para->buf;
    fld_name = (char*)p_memory_para->buf2;


    if (CTC_ASW_INVALID_TBL_ID != p_memory_para->param[3])
    {
        reg_tbl_id = p_memory_para->param[3];
        drv_asw_get_tbl_id_by_string(lchip, &reg_tbl_id, (char*)reg_name);
    }
    else
    {
        if (DRV_E_NONE != drv_asw_get_tbl_id_by_string(lchip, &reg_tbl_id, reg_name)
            || (0 == TABLE_MAX_INDEX(lchip, reg_tbl_id)))
        {
            CTC_ASW_PRINT("%% Not found %s\n", reg_name);
            ret = CLI_ERROR;
            goto WRITE_TABLE_ERROR;
        }
    }

    if ((reg_tbl_id) >= MaxTblId_t)
    {
        ret = CLI_ERROR;
        goto WRITE_TABLE_ERROR;
    }

    if (p_memory_para->param[4] != 0xFFFFFFFF)
    {
        fld_id = p_memory_para->param[4];

        drv_asw_get_field_string_by_id(lchip, reg_tbl_id , fld_id, fld_name);
    }
    else
    {
        tmp_reg_tbl_id = reg_tbl_id;
        if (DRV_E_NONE != drv_asw_get_field_id_by_string(lchip, tmp_reg_tbl_id, &fld_id, fld_name))
        {
            CTC_ASW_PRINT("%% Not found %s\n", fld_name);
            ret = CLI_ERROR;
            goto WRITE_TABLE_ERROR;
        }
    }

    index = index_temp;

    /*1.read firstly*/
    if (TABLE_MAX_INDEX(lchip, reg_tbl_id) == 0)
    {
        DRV_DBG_INFO("\nERROR! Operation on an empty table! TblID: %d, Name:%s, file:%s line:%d function:%s\n",reg_tbl_id, TABLE_NAME(lchip, reg_tbl_id), __FILE__,__LINE__,__FUNCTION__);
        ret = DRV_E_INVALID_TBL;
        goto WRITE_TABLE_ERROR;
    }
    cmd = DRV_IOR(reg_tbl_id, DRV_ENTRY_FLAG);
    if (TBL_SRAM_MASK == drv_asw_get_table_type(lchip, reg_tbl_id))
    {
        field_entry.data_entry = value;
        field_entry.mask_entry = mask;

        ret = DRV_MASK_IOCTL(lchip, index, cmd, &field_entry);

    }
    else
    {
        if (TBL_HASH == drv_asw_get_table_type(lchip, reg_tbl_id))
        {
            cmd = DRV_IOHL(reg_tbl_id, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, index, cmd, value);
        }
        else
        {
            ret = DRV_IOCTL(lchip, index, cmd, value);
        }
    }
    /*2.write secondly*/
    cmd = DRV_IOW(reg_tbl_id, DRV_ENTRY_FLAG);
    if (TBL_SRAM_MASK == drv_asw_get_table_type(lchip, reg_tbl_id))
    {
        drv_asw_set_field(lchip, reg_tbl_id, fld_id, field_entry.data_entry, p_value);
        drv_asw_set_field(lchip, reg_tbl_id, fld_id, field_entry.mask_entry, p_mask);
        ret = ret?ret:DRV_MASK_IOCTL(lchip, index, cmd, &field_entry);
    }
    else
    {
        drv_asw_set_field(lchip, reg_tbl_id, fld_id, value, p_value);
        if (TBL_HASH == drv_asw_get_table_type(lchip, reg_tbl_id))
        {
            cmd = DRV_IOHA(reg_tbl_id, DRV_ENTRY_FLAG);
            ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, value);
        }
        else
        {
            ret = ret?ret:DRV_IOCTL(lchip, index, cmd, value);
        }
    }

    if (ret < 0)
    {
        CTC_ASW_PRINT("%% Write %s index %d failed %d\n",  "tbl-reg", index_temp, ret);
    }

WRITE_TABLE_ERROR:
    if (mask)
    {
        sal_free(mask);
    }
    if (value)
    {
        sal_free(value);
    }
    if (fld_name_temp)
    {
        sal_free(fld_name_temp);
    }

    return ret;
}

CTC_CLI(cli_asw_list_tbl,
        cli_asw_list_tbl_cmd,
        "list STRING:TBL_NAME (grep SUB_STR | )(detail |)",
        "List tables",
        "Substring of table name",
        "Grep sub string from result",
        "Sub string",
        "Detail display")
{
    ctc_asw_memory_para_t* req = &memory_para_com;
    uint8 index = 0;
    int32 ret = 0;

    sal_memset(req, 0, sizeof(ctc_asw_memory_para_t));
    req->type = CTC_ASW_MEMORY_LIST;

    if (argc > 0)
    {
        sal_strncpy((char*)req->buf, argv[0], CTC_ASW_RW_BUF_SIZE-1);
    }

    index = CTC_CLI_GET_ARGC_INDEX("grep");
    if (index != 0xFF)
    {
        sal_strncpy((char*)req->buf2, argv[index+1], CTC_ASW_RW_BUF_SIZE-1);
        req->grep = 1;
    }

    index = CTC_CLI_GET_ARGC_INDEX("detail");
    if (index != 0xFF)
    {
        req->detail = 1;
    }

    ret = _ctc_asw_asw_memory_list_table(vty, g_api_lchip, req);
    if (ret < 0)
    {
        CTC_ASW_PRINT("list table ret=%d\n", ret);
        return CLI_ERROR;
    }

    return CLI_SUCCESS;
}

CTC_CLI(cli_asw_read_reg_or_tbl,
        cli_asw_read_reg_or_tbl_cmd,
        "read STRING:TBL_NAME_ID INDEX ( direct | count COUNT (step STEP | ) | ) (inst INST_ID |)  (grep SUB_STR | )",
        "Read table or register",
        "Table name like [DsMac] or table id like [4870]",
        "Table index value <0-0xFFFFFFFF>",
        "Read table by direct I/O, otherwise by ACC I/O",
        "The counts of sequential registers to read from the index",
        "Counts",
        "Step how many count. Default:1",
        "Step count. 2 means 0 2 4...",
        "Table Instance",
        "Table Instance ID",
        "Grep",
        "Regex")
{
    ctc_asw_memory_para_t* req = &memory_para_com;
    uint32 index = 0;
    uint32 count = 1;
    uint32 tbl_id = 0;
    uint8 step = 1;
    uint8 arg_index = 0;
    uint32 inst_id = 0;
    char *ins_info = NULL;
    int32 ret = 0;

    sal_memset(req, 0, sizeof(ctc_asw_memory_para_t));
    req->type = CTC_ASW_MEMORY_READ;

    /*get tbl name or tbl id*/
    sal_strncpy((char*)req->buf, argv[0], CTC_ASW_RW_BUF_SIZE-1);
    tbl_id = CTC_ASW_INVALID_TBL_ID;
    if ((req->buf[0] >= '0') && (req->buf[0] <= '9'))
    {
        CTC_CLI_GET_UINT32_RANGE("table-id", tbl_id, argv[0], 0, CTC_MAX_UINT32_VALUE);
    }

    ins_info = sal_strstr((char*)req->buf, ".");
    if (NULL != ins_info)
    {
        sal_sscanf(ins_info + 1, "%u", &inst_id);
        *ins_info = '\0';
    }

    /*get tbl index*/
    CTC_CLI_GET_UINT32_RANGE("Tbl-index", index, argv[1], 0, 0xFFFFFFFF);

    arg_index = CTC_CLI_GET_ARGC_INDEX("direct");
    if (arg_index != 0xFF)
    {
        req->direct_io = 1;
    }
    arg_index = CTC_CLI_GET_ARGC_INDEX("count");
    if (arg_index != 0xFF)
    {
        CTC_CLI_GET_UINT32_RANGE("count", count, argv[arg_index + 1], 0, CTC_MAX_UINT32_VALUE);
    }
    arg_index = CTC_CLI_GET_ARGC_INDEX("step");
    if (arg_index != 0xFF)
    {
        CTC_CLI_GET_UINT8_RANGE("step", step, argv[arg_index + 1], 0, CTC_MAX_UINT8_VALUE);
    }

    arg_index = CTC_CLI_GET_ARGC_INDEX("inst");
    if (arg_index != 0xFF)
    {
        CTC_CLI_GET_UINT32_RANGE("inst", inst_id, argv[arg_index + 1], 0, CTC_MAX_UINT32_VALUE);
    }
    index = (index&0xFFFFFF) + (inst_id << 24);

    arg_index = CTC_CLI_GET_ARGC_INDEX("grep");
    if (arg_index != 0xFF)
    {
        sal_strncpy((char*)req->buf2, argv[arg_index+1], CTC_ASW_RW_BUF_SIZE-1);
        req->grep = 1;
    }

    req->param[1] = g_api_lchip;
    req->param[2] = index;
    req->param[3] = tbl_id;
    req->param[4] = count;
    req->param[5] = step;

    ret = _ctc_asw_asw_memory_read_table(vty, g_api_lchip, req);
    if (ret < 0)
    {
        CTC_ASW_PRINT("read table ret=%d\n", ret);
        return CLI_ERROR;
    }
    return ret;
}


CTC_CLI(cli_asw_write_reg_or_tbl,
        cli_asw_write_reg_or_tbl_cmd,
        "write STRING:TBL_NAME_ID INDEX STRING:FLD_NAME_ID VALUE ( mask MASK| direct | ) (inst INST_ID |)",
        "Write table or register",
        "Table name like [DsMac] or table id like [4870]",
        "Table index value <0-0xFFFFFFFF>",
        "Field name or field id",
        "Value",
        "Tcam mask",
        "Tcam mask",
        "Write table by direct I/O, otherwise by ACC I/O",
        "Table Instance",
        "Table Instance ID")
{
    ctc_asw_memory_para_t* req = &memory_para_com;
    uint32 field_id = 0;
    uint32 index = 0;
    static uint32 value[CTC_ASW_MAX_ENTRY_WORD] = {0};
    static uint32 mask[CTC_ASW_MAX_ENTRY_WORD] = {0};
    uint32 tbl_id = 0;
    uint8 arg_index = 0;
    uint32 inst_id = 0;
    char *ins_info = NULL;
    int32 ret = 0;

    sal_memset(req, 0, sizeof(ctc_asw_memory_para_t));
    sal_memset(&value, 0, sizeof(value));
    sal_memset(&mask, 0, sizeof(mask));
    req->type = CTC_ASW_MEMORY_WRITE;

    /*get tbl name or tbl id*/
    sal_strncpy((char*)req->buf, argv[0], CTC_ASW_RW_BUF_SIZE-1);
    tbl_id = CTC_ASW_INVALID_TBL_ID;
    if ((req->buf[0] >= '0') && (req->buf[0] <= '9'))
    {
        CTC_CLI_GET_UINT32_RANGE("table-id", tbl_id, argv[0], 0, CTC_MAX_UINT32_VALUE);
    }
    ins_info = sal_strstr((char*)req->buf, ".");
    if (NULL != ins_info)
    {
        sal_sscanf(ins_info + 1, "%u", &inst_id);
        *ins_info = '\0';
    }

    /*get tbl index*/
    CTC_CLI_GET_UINT32_RANGE("Tbl-index", index, argv[1], 0, 0xFFFFFFFF);

    /*get field name*/
    sal_strncpy((char*)req->buf2, argv[2], CTC_ASW_RW_BUF_SIZE-1);
    field_id = 0xFFFFFFFF;
    if ((req->buf2[0] >= '0') && (req->buf2[0] <= '9'))
    {
        CTC_CLI_GET_UINT32_RANGE("field-id", field_id, argv[2], 0, CTC_MAX_UINT32_VALUE);
    }

    /*get field value*/
    CTC_CLI_GET_INTEGER_N("fld-value", (uint32 *)(value), argv[3]);
    arg_index = CTC_CLI_GET_ARGC_INDEX("mask");
    if (arg_index != 0xFF)
    {
        CTC_CLI_GET_INTEGER_N("fld-value", (uint32 *)(mask), argv[arg_index + 1]);
    }

    arg_index = CTC_CLI_GET_ARGC_INDEX("inst");
    if (arg_index != 0xFF)
    {
        CTC_CLI_GET_UINT32_RANGE("inst", inst_id, argv[arg_index + 1], 0, CTC_MAX_UINT32_VALUE);
    }
    index = (index&0xFFFFFF) + (inst_id << 24);

    arg_index = CTC_CLI_GET_ARGC_INDEX("direct");
    if (arg_index != 0xFF)
    {
        req->direct_io = 1;
    }

    req->param[1] = g_api_lchip;
    req->param[2] = index;
    req->param[3] = tbl_id;
    req->param[4] = field_id;
    sal_memcpy(req->value, value, CTC_ASW_MAX_ENTRY_WORD*4);
    sal_memcpy(req->mask, mask, CTC_ASW_MAX_ENTRY_WORD*4);

    ret = _ctc_asw_asw_memory_write_table(vty, g_api_lchip, req);
    if (ret < 0)
    {
        CTC_ASW_PRINT("read table ret=%d\n", ret);
        return CLI_ERROR;
    }

    return CLI_SUCCESS;
}

CTC_CLI(cli_asw_read_address,
    cli_asw_read_address_cmd,
    "read address ADDR_OFFSET (count COUNT |)",
    "read address value cmd",
    "read address 0xXXXXXXXX",
    "address value",
    "replicate time",
    "replicate time")
{
    int32 ret = CLI_SUCCESS;
    uint32 address_offset = 0, rep_time = 1;
    uint32 tmp_i = 0;
    uint32 tmp_value = 0;
    uint8 index = 0;

    CTC_CLI_GET_UINT32("addressOffset", address_offset, argv[0]);

    index = CTC_CLI_GET_ARGC_INDEX("count");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT32("count", rep_time, argv[index + 1]);
    }

    for (tmp_i = 0 ; tmp_i < rep_time; tmp_i++)
    {
        drv_asw_chip_read(g_api_lchip, address_offset, &tmp_value, 4);
        CTC_ASW_PRINT("Address 0x%08x: 0x%08x\n", address_offset, tmp_value);
        address_offset = address_offset + 4;
    }

    return ret;
}

CTC_CLI(cli_asw_write_address,
    cli_asw_write_address_cmd,
    "write address ADDR_OFFSET WRITE_VALUE",
    "write value to address cmd",
    "write address 0xXXXXXXXX <value>",
    "address value",
    "value to write")
{
    uint32 address_offset = 0, value = 0;
    int32 ret = CLI_SUCCESS;

    CTC_CLI_GET_UINT32("address", address_offset, argv[0]);
    CTC_CLI_GET_UINT32("value", value, argv[1]);
    ret = drv_asw_chip_write(g_api_lchip, address_offset, &value, 4);
    if (ret < CLI_SUCCESS)
    {
        CTC_ASW_PRINT("0x%08x address write ERROR! Value = 0x%08x\n", address_offset, value);
    }

    return CLI_SUCCESS;
}

#define CTC_ASW_INGRESS_DISCARD_CNT 32
#define CTC_ASW_EGRESS_DISCARD_CNT 8
CTC_CLI(cli_asw_show_discard,
    cli_asw_show_discard_cmd,
    "show discard gport GPORT (ingress|egress)",
    "Show",
    "Show discard info",
    "Gport",
    "Gport Value",
    "Ingress",
    "Egress")
{
    uint32 gport = 0;
    uint32 frame_cnt = 0;
    uint8 index = 0;
    uint32 base_idx = 0;
    uint32 cmd = 0;
    uint8 lchip = g_api_lchip;
    ds_t ds;
    char* igs_discard[CTC_ASW_INGRESS_DISCARD_CNT] = {"jumbo packet error", "eap", "sa0", "tag pkt", "untag pkt", "1ptag pkt", "stp", "pmac", "smac", "vlan mapping drop","unknow unicast", "unknow mcast", "storm ctl bc", "ivt drop", "vlan mem chk", "vlan not exist", "new sa learn",
                                                      "da black list", "sa black list", "station move", "over mac limit", "acl", "reserve", "reserve", "reserve", "security", "dos", "no forwarding", "mask", "stpid chk fail", "bucket full", "reserve"};
    char* egs_discard[CTC_ASW_EGRESS_DISCARD_CNT] = {"eap", "vlan mem chk", "egress vlan not exist", "mstp", "reserve", "reserve", "reserve", "reserve"};

    char* igs_discard_detail[CTC_ASW_INGRESS_DISCARD_CNT] = {"jumbo packet or cpu mac with no ptag packet will be dropped(CpuMacCtrl.noPtagDrop = 1)", 
        "support no dotx1x authentication, only EAPOL packet can pass(IngressPort.eapBlock = 1)", 
        "drop sa = all zero or muticast or broadcast packet(ArlCtrlReg.sa0OrMcDrop = 1)", "IngressPort.noTagPkt = 1discard this packet if it is tagged packet",
        "discard this packet if it is untagged(IngressPort.noUntagPkt = 1)", "discard this packet if it is 802.1P packet(IngressPort.no1pPkt = 1)", 
        "stp blocking state discard", "pdu private mac protocol packet discard", "pdu smac protocol packet discard", 
        "if hit default vlan and IvmTable.drop is 1,packet is dropped","unknow unicast packet drop(IvtProfile.ulfDrop = 1)", "unknow muticast packet(IvtProfile.mlfDrop = 1)", 
        "broadcast packet drop（IvtProfile.bcDrop = 1）",
        "Drop the packet even the membership is allowed（IvtProfile.drop = 1）", "if hit IvtTable and member check wrong", "IvtTable invalid", "new mac sa packet learn drop(MacLkupCtrl.newsaToDrop = 1)",
        "da black list(ArlTable.dmacFilter = 1)", "sa black list(ArlTable.smacFilter = 1)", "station move(MacLkupCtrl.moveToDrop = 1)", "over limit(MacLkupCtrl.overlimitToDrop = 1)", 
        "acl is matched(AclBaseAction.drop = 1)", "reserve", "reserve", "reserve", 
        "ip sa = ip da, mac sa = mac da(SecurityFilterRule.ipLand/macLand = 1)", "dos, illegal mac/ip sa, tcp sequence number=0, control bits=0, sync-ack flooding", 
        "no forwarding, dest bitmap is 0", "no forwarding, dest bitmap is not 0, after mask become 0", "check vlan tpid, if fail,drop packet(IngressPort.vlanTpidVerifyEnable = 1)", 
        "arl learn mac sa not found and bucket full, this packet will drop(MacLkupCtrl.bucketFullToDrop = 1)", "reserve"};
    char* egs_discard_detail[CTC_ASW_EGRESS_DISCARD_CNT] = {"support no dotx1x authentication, only EAPOL packet can pass(EgressPort.eapBlock = 1)", "if hit EvtTable and member check wrong", 
        "EvtTable.valid but packet miss", "mstp state is 1(EgressPort.stpBlock = 1 or EvtTable.valid is 1)", "reserve", "reserve", "reserve", "reserve"};

    CTC_CLI_GET_INTEGER("gport", gport, argv[0]);

    index = CTC_CLI_GET_ARGC_INDEX("ingress");
    if (0xFF != index)
    {
        CTC_ASW_PRINT("Discard gport %d ingress:\n", gport);
        base_idx = gport*CTC_ASW_INGRESS_DISCARD_CNT;
        ctc_cli_out("\n%-20s%-12s%-22s\n", "REASON", "CNT", "DETAIL");
        ctc_cli_out("-----------------------------------------------------------------------------------------------\n");
        for(index=0;index<CTC_ASW_INGRESS_DISCARD_CNT; index++)
        {
            cmd = DRV_IOR(IresolutionDropMib_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, base_idx+index, cmd, &ds);
            frame_cnt = GetIresolutionDropMib(V,frameCnt_f, &ds);
            if (frame_cnt != 0)
            {
                CTC_ASW_PRINT("%-20s%-12d%-22s\n", igs_discard[index], frame_cnt, igs_discard_detail[index]);
            }
        }
    }
    else
    {
        CTC_ASW_PRINT("Discard gport %d egress:\n", gport);
        base_idx = gport*CTC_ASW_EGRESS_DISCARD_CNT;
        ctc_cli_out("\n%-20s%-12s%-22s\n", "REASON", "CNT", "DETAIL");
        ctc_cli_out("-----------------------------------------------------------------------------------------------\n");
        for(index=0;index<CTC_ASW_EGRESS_DISCARD_CNT; index++)
        {
            cmd = DRV_IOR(EresolutionDropMib_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, base_idx+index, cmd, &ds);
            frame_cnt = GetEresolutionDropMib(V,frameCnt_f, &ds);
            if (frame_cnt != 0)
            {
                CTC_ASW_PRINT("%-20s%-12d%-22s\n", egs_discard[index], frame_cnt, egs_discard_detail[index]);
            }
        }
    }

    return CLI_SUCCESS;
}


CTC_CLI(cli_asw_clear_discard,
    cli_asw_clear_discard_cmd,
    "clear discard gport GPORT (ingress|egress)",
    "Clear",
    "Clear discard",
    "Gport",
    "Gport Value",
    "Ingress",
    "Egress")
{
    uint32 gport = 0;
    uint8 index = 0;
    uint32 base_idx = 0;
    uint32 cmd = 0;
    uint8 lchip = g_api_lchip;
    ds_t ds;

    CTC_CLI_GET_INTEGER("gport", gport, argv[0]);

    /*1. set discard stats to read and clear*/
    cmd = DRV_IOR(GlobalCtrl_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, 0, cmd, &ds);
    SetGlobalCtrl(V, cntRcEn_f, &ds, 1);
    cmd = DRV_IOW(GlobalCtrl_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, 0, cmd, &ds);

    /*2. read and clear all discard stats*/
    index = CTC_CLI_GET_ARGC_INDEX("ingress");
    if (0xFF != index)
    {
        base_idx = gport*CTC_ASW_INGRESS_DISCARD_CNT;
        for(index=0;index<CTC_ASW_INGRESS_DISCARD_CNT; index++)
        {
            cmd = DRV_IOR(IresolutionDropMib_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, base_idx+index, cmd, &ds);
        }
    }
    else
    {
        base_idx = gport*CTC_ASW_EGRESS_DISCARD_CNT;
        for(index=0;index<CTC_ASW_EGRESS_DISCARD_CNT; index++)
        {
            cmd = DRV_IOR(EresolutionDropMib_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, base_idx+index, cmd, &ds);
        }
    }

    /*3. set discard stats to read only*/
    cmd = DRV_IOR(GlobalCtrl_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, 0, cmd, &ds);
    SetGlobalCtrl(V, cntRcEn_f, &ds, 0);
    cmd = DRV_IOW(GlobalCtrl_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, 0, cmd, &ds);

    return CLI_SUCCESS;
}

int32
ctc_asw_diag_cli_init(uint8 cli_tree_mode)
{
    install_element(cli_tree_mode, &cli_asw_list_tbl_cmd);
    install_element(cli_tree_mode, &cli_asw_read_reg_or_tbl_cmd);
    install_element(cli_tree_mode, &cli_asw_write_reg_or_tbl_cmd);
    install_element(cli_tree_mode, &cli_asw_read_address_cmd);
    install_element(cli_tree_mode, &cli_asw_write_address_cmd);
    install_element(cli_tree_mode, &cli_asw_show_discard_cmd);
    install_element(cli_tree_mode, &cli_asw_clear_discard_cmd);

    return CLI_SUCCESS;
}




